package compoundDB.database;

import static org.junit.Assert.*;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

import compoundDB.core.Compound;
import compoundDB.database.container.ColumnField;
import compoundDB.database.container.SearchOption;

/**
 * This class tests the CachedQueryReader implementation of the QueryReader interface.
 * 
 * @author Kohl Bromwich
 */
public class CachedQueryReaderTest
{
	@Test
	public void testGetCompoundCount() throws ClassNotFoundException, SQLException
	{
		DatabaseTests.setupTestDatabase();
		DatabaseTests.populateDatabase();
		DBManager dbm = new DBManager();
		dbm.openDatabaseConnection();
		
		List<ColumnField> cols = dbm.getCompoundTableColumns();
		
		// Setup search filters
		SearchOption so1 = SearchOption.createSearchRange(cols.get(0), 2, 4);
		
		List<SearchOption> sos = new ArrayList<SearchOption>();
		sos.add(so1);
		
		// Perform search
		QueryReader rdr = dbm.searchCompounds(sos);
		assertTrue(rdr.getCompoundCount() == 3);
		
		// Setup search filters
		so1 = SearchOption.createSearchRange(cols.get(0), 1, 5);
		
		sos = new ArrayList<SearchOption>();
		sos.add(so1);
		
		// Perform search
		rdr = dbm.searchCompounds(sos);
		assertTrue(rdr.getCompoundCount() == 5);
		
		dbm.closeDatabaseConnection();
	}
	
	@Test
	public void testGetCompounds() throws ClassNotFoundException, SQLException
	{
		DatabaseTests.setupTestDatabase();
		DatabaseTests.populateDatabase();
		Connection conn = DatabaseTests.getNewConnection();
		Statement st = conn.createStatement();
		st.executeUpdate("INSERT INTO compounds VALUES(0, 6, NULL, 'smiles6', NULL, NULL, 'notes6');");
		st.executeUpdate("INSERT INTO compound_names VALUES(6, 'comp61')");
		st.executeUpdate("INSERT INTO compound_names VALUES(6, 'comp62')");
		st.close();
		conn.close();
		DBManager dbm = new DBManager();
		dbm.openDatabaseConnection();
		
		List<ColumnField> cols = dbm.getCompoundTableColumns();
		
		// Setup search filters
		SearchOption so1 = SearchOption.createSearchContains(cols.get(3), "smiles");
		SearchOption so2 = SearchOption.createSearchRange(cols.get(0), 2, 6);
		
		List<SearchOption> sos = new ArrayList<SearchOption>();
		sos.add(so1);
		sos.add(so2);
		
		// Perform search
		QueryReader rdr = dbm.searchCompounds(sos);
		assertTrue(rdr.getCompoundCount() == 5);
		
		// Check results
		List<Compound> comps = rdr.getCompounds(1, 25);
		assertTrue(comps.size() == 5);
		
		assertTrue(comps.get(0).getGUID() == 2);
		assertTrue(comps.get(0).getOwnerID() == 2);
		assertTrue(comps.get(0).getNames().size() == 2);
		assertTrue(comps.get(0).getNames().get(0).equals("comp21"));
		assertTrue(comps.get(0).getNames().get(1).equals("comp22"));
		assertTrue(comps.get(0).getProperty("tags").equals("tags2"));

		assertTrue(comps.get(1).getGUID() == 3);
		assertTrue(comps.get(1).getOwnerID() == 3);
		assertTrue(comps.get(1).getNames().size() == 1);
		assertTrue(comps.get(1).getNames().get(0).equals("comp31"));
		assertTrue(comps.get(1).getProperty("tags").equals("tags3"));

		assertTrue(comps.get(4).getGUID() == 6);
		assertTrue(comps.get(4).getOwnerID() == 6);
		assertTrue(comps.get(4).getNames().size() == 2);
		assertTrue(comps.get(4).getNames().get(0).equals("comp61"));
		assertTrue(comps.get(4).getNames().get(1).equals("comp62"));
		assertTrue(comps.get(4).getProperty("tags") == null);
		assertTrue(comps.get(4).getProperty("smiles").equals("smiles6"));
		assertTrue(comps.get(4).getProperty("links") == null);
		assertTrue(comps.get(4).getProperty("notes").equals("notes6"));
		
		// Test throws IllegalArgument
		try {
			rdr.getCompounds(0, 2);
			fail("Should throw an exception when start compound is less than 1");
		}catch(IllegalArgumentException exc){}
		dbm.closeDatabaseConnection();
	}
	
	@Test
	public void testClose() throws ClassNotFoundException, SQLException
	{
		DatabaseTests.setupTestDatabase();
		DatabaseTests.populateDatabase();
		DBManager dbm = new DBManager();
		dbm.openDatabaseConnection();
		
		List<ColumnField> cols = dbm.getCompoundTableColumns();
		
		// Setup search filters
		SearchOption so1 = SearchOption.createSearchRange(cols.get(0), 2, 4);
		
		List<SearchOption> sos = new ArrayList<SearchOption>();
		sos.add(so1);
		
		// Perform search
		QueryReader rdr = dbm.searchCompounds(sos);
		assertTrue(rdr.getCompoundCount() == 3);
		
		rdr.close();
		
		// Test it can't be read anymore
		try{
			rdr.getCompoundCount();
			fail("Shouldn't be able to do stuff when reader is closed.");
		}catch(SQLException exc){}
		try{
			rdr.getCompounds(1, 1);
			fail("Shouldn't be able to do stuff when reader is closed.");
		}catch(SQLException exc){}
		
		dbm.closeDatabaseConnection();
	}
	
	@Test
	public void testSeek_GetCompound() throws ClassNotFoundException, SQLException
	{
		DatabaseTests.setupTestDatabase();
		DatabaseTests.populateDatabase();
		Connection conn = DatabaseTests.getNewConnection();
		Statement st = conn.createStatement();
		st.executeUpdate("INSERT INTO compounds VALUES(0, 6, NULL, 'smiles6', NULL, NULL, 'notes6');");
		st.executeUpdate("INSERT INTO compound_names VALUES(6, 'comp61')");
		st.executeUpdate("INSERT INTO compound_names VALUES(6, 'comp62')");
		st.close();
		conn.close();
		DBManager dbm = new DBManager();
		dbm.openDatabaseConnection();
		
		List<ColumnField> cols = dbm.getCompoundTableColumns();
		
		// Setup search filters
		SearchOption so1 = SearchOption.createSearchContains(cols.get(3), "smiles");
		SearchOption so2 = SearchOption.createSearchRange(cols.get(0), 2, 6);
		
		List<SearchOption> sos = new ArrayList<SearchOption>();
		sos.add(so1);
		sos.add(so2);
		
		// Perform search
		QueryReader rdr = dbm.searchCompounds(sos);
		assertTrue(rdr.getCompoundCount() == 5);
		
		// Check results
		rdr.seek(1);
		Compound comp = rdr.getCompound();
		
		assertTrue(comp.getGUID() == 2);
		assertTrue(comp.getOwnerID() == 2);
		assertTrue(comp.getNames().size() == 2);
		assertTrue(comp.getNames().get(0).equals("comp21"));
		assertTrue(comp.getNames().get(1).equals("comp22"));
		assertTrue(comp.getProperty("tags").equals("tags2"));
		
		rdr.seek(2);
		comp = rdr.getCompound();

		assertTrue(comp.getGUID() == 3);
		assertTrue(comp.getOwnerID() == 3);
		assertTrue(comp.getNames().size() == 1);
		assertTrue(comp.getNames().get(0).equals("comp31"));
		assertTrue(comp.getProperty("tags").equals("tags3"));

		rdr.seek(5);
		comp = rdr.getCompound();
		
		assertTrue(comp.getGUID() == 6);
		assertTrue(comp.getOwnerID() == 6);
		assertTrue(comp.getNames().size() == 2);
		assertTrue(comp.getNames().get(0).equals("comp61"));
		assertTrue(comp.getNames().get(1).equals("comp62"));
		assertTrue(comp.getProperty("tags") == null);
		assertTrue(comp.getProperty("smiles").equals("smiles6"));
		assertTrue(comp.getProperty("links") == null);
		assertTrue(comp.getProperty("notes").equals("notes6"));
		
		// Test throws IllegalArgument
		try {
			rdr.seek(0);
			fail("Should throw an exception when seeking 0");
		}catch(SQLException exc){}
		
		dbm.closeDatabaseConnection();
	}
}
